#pragma once

#include "BufferManager.h"
#include "Page.h"
#include <unordered_map>
#include <vector>
#include <string>
#include <memory>

namespace MiniDB
{

    // Table metadata structure
    struct TableMetadata
    {
        std::string table_name;
        std::vector<int> page_ids; // Pages allocated to this table
        size_t record_count;
        size_t total_size;

        TableMetadata() : record_count(0), total_size(0) {}
        TableMetadata(const std::string &name)
            : table_name(name), record_count(0), total_size(0) {}
    };

    // Record structure for simple storage
    struct Record
    {
        int id;
        std::string data;
        bool is_deleted;

        Record(int record_id = 0, const std::string &record_data = "")
            : id(record_id), data(record_data), is_deleted(false) {}

        size_t size() const
        {
            return sizeof(id) + data.size() + sizeof(is_deleted);
        }
    };

    // Join result structure for multi-table queries
    struct JoinResult
    {
        int id;
        std::unordered_map<std::string, std::string> table_data; // table_name -> data

        JoinResult(int join_id = 0) : id(join_id) {}
    };

    class StorageManager
    {
    public:
        StorageManager(size_t buffer_size = 100, ReplacementPolicy policy = ReplacementPolicy::LRU);
        ~StorageManager();

        // Table management
        bool createTable(const std::string &table_name);
        bool dropTable(const std::string &table_name);
        bool restoreTableMetadata(const std::string &table_name, int root_page_id, size_t record_count, size_t total_size);
        bool tableExists(const std::string &table_name) const;
        std::vector<std::string> getTableNames() const;

        // Page operations (unified interface)
        std::shared_ptr<Page> getPage(int page_id);
        bool readPage(int page_id, void *buffer, size_t size);
        bool writePage(int page_id, const void *data, size_t size);
        bool flushPage(int page_id);
        bool flushAll();
        void releasePage(int page_id);

        // Record operations
        bool insertRecord(const std::string &table_name, const Record &record);
        bool deleteRecord(const std::string &table_name, int record_id);
        bool updateRecord(const std::string &table_name, int record_id, const Record &new_record);
        std::vector<Record> getRecords(const std::string &table_name);
        Record getRecord(const std::string &table_name, int record_id);

        // Buffer management
        const CacheStats &getCacheStats() const;
        void resetCacheStats();
        void resizeBuffer(size_t new_size);
        void setReplacementPolicy(ReplacementPolicy policy);

        // Multi-table operations
        std::vector<JoinResult> joinTables(const std::vector<std::string> &table_names, const std::string &join_condition = "");
        std::vector<JoinResult> joinTablesWithCondition(const std::vector<std::string> &table_names,
                                                       const std::string &join_type, const std::string &condition);

        // Advanced join implementations
        void performInnerJoinAdvanced(const std::vector<std::string> &table_names,
                                    const std::vector<std::vector<Record>> &all_records,
                                    std::vector<JoinResult> &results,
                                    const std::string &condition);
        void performLeftJoinAdvanced(const std::vector<std::string> &table_names,
                                   const std::vector<std::vector<Record>> &all_records,
                                   std::vector<JoinResult> &results,
                                   const std::string &condition);
        void performRightJoinAdvanced(const std::vector<std::string> &table_names,
                                    const std::vector<std::vector<Record>> &all_records,
                                    std::vector<JoinResult> &results,
                                    const std::string &condition);
        void performFullJoinAdvanced(const std::vector<std::string> &table_names,
                                   const std::vector<std::vector<Record>> &all_records,
                                   std::vector<JoinResult> &results,
                                   const std::string &condition);
        void performCrossJoin(const std::vector<std::string> &table_names,
                            const std::vector<std::vector<Record>> &all_records,
                            std::vector<JoinResult> &results);

        // Helper methods
        std::tuple<std::string, std::string, std::string, std::string> parseJoinCondition(const std::string &condition);
        bool matchesJoinCondition(const Record &left_rec, const Record &right_rec,
                                const std::string &left_col, const std::string &right_col);
        bool resultsAreEqual(const JoinResult &result1, const JoinResult &result2);
        size_t findTableIndex(const std::vector<std::string> &table_names, const std::string &table_name);

        // Utility methods
        size_t getTableSize(const std::string &table_name) const;
        size_t getRecordCount(const std::string &table_name) const;
        void printTableInfo(const std::string &table_name) const;

        // Data persistence methods
        bool saveDatabaseState();
        bool loadDatabaseState();
        bool saveTableMetadata();
        bool loadTableMetadata();

    private:
        // Private methods
        int allocatePage(const std::string &table_name);
        void deallocatePage(int page_id, const std::string &table_name);
        bool serializeRecord(const Record &record, std::vector<char> &buffer);
        bool deserializeRecord(const std::vector<char> &buffer, Record &record, size_t &bytes_read);

        // Data members
        std::unique_ptr<BufferManager> buffer_manager_;
        std::unordered_map<std::string, TableMetadata> tables_;
        std::unordered_map<int, std::string> page_to_table_; // page_id -> table_name
        int next_page_id_;

        // Constants
        static const size_t MAX_RECORDS_PER_PAGE;
    };

} // namespace MiniDB
